package fun.wxy.camera.fragment;

import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;

import com.saintdeem.palmvein.SDPVUnifiedAPI;
import com.saintdeem.palmvein.bean.EnrollPicture;
import com.saintdeem.palmvein.device.SDPVDeviceConstant;
import com.saintdeem.palmvein.device.bean.CaptureResult;
import com.saintdeem.palmvein.device.bean.DeviceMsg;
import com.saintdeem.palmvein.service.bean.DetectRoiResult;
import com.saintdeem.palmvein.service.bean.ServiceMsg;
import com.saintdeem.palmvein.util.BitmapUtil;
import com.saintdeem.palmvein.util.Constant;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Objects;
import java.util.concurrent.LinkedBlockingQueue;

import fun.wxy.camera.R;
import fun.wxy.camera.util.PalmDeviceFrameUtil;

public class PalmFragment extends Fragment {

    private static final String TAG = "PalmFragment";
    private static final String ACTION_USB_PERMISSION = "fun.wxy.camera.USB_PERMISSION";

    public static final int PALM_DETECT_MAX = 500;

    private static final int PALM_USB_PRODUCT_ID = 4097;
    private static final int PALM_USB_VENDOR_ID = 31109;

    private Context context;
    private SDPVUnifiedAPI unifiedApi;
    private ImageView palmPreviewImg;
    private TextView collectionTipTxt;

    // USB权限相关
    private BroadcastReceiver usbPermissionReceiver;
    private UsbManager usbManager;
    private boolean hasUsbPermission = false;

    // 线程管理
    private PalmRecognizeThread palmRecognizeThread;
    private PalmDetectThread palmDetectThread;
    private DeviceTookImage deviceTookImage;

    private final ColorDrawable colorDrawable = new ColorDrawable(Color.BLACK);
    private final LinkedBlockingQueue<EnrollPicture> detectResultQueue = new LinkedBlockingQueue<>(3);

    private static final int IMG_WIDTH = 400;
    private static final int IMG_HEIGHT = 600;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        context = requireContext();
        initUsbPermissionSystem();
        initPalmSDK();
    }

    private void initUsbPermissionSystem() {
        usbPermissionReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (ACTION_USB_PERMISSION.equals(action)) {
                    handleUsbPermissionResult(intent);
                }
            }
        };

        usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

        context.registerReceiver(usbPermissionReceiver, new IntentFilter(ACTION_USB_PERMISSION));
    }

    private void handleUsbPermissionResult(Intent intent) {
        synchronized (this) {
            UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
            if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                if (device != null) {
                    if (device.getProductId() == PALM_USB_PRODUCT_ID && device.getVendorId() == PALM_USB_VENDOR_ID) {
                        hasUsbPermission = true;
                        startDeviceOperations();
                    }
                }
            } else {
                showPermissionDenied();
            }
        }
    }

    private void initPalmSDK() {
        try {
            unifiedApi = SDPVUnifiedAPI.getInstance();

            InputStream is = context.getResources().openRawResource(R.raw.license);
            File tempFile = File.createTempFile("license", ".dat", context.getCacheDir());
            try (FileOutputStream fos = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[1024];
                int length;
                while ((length = is.read(buffer)) > 0) {
                    fos.write(buffer, 0, length);
                }
                ServiceMsg<String> serviceMsg = unifiedApi.initService(tempFile.getAbsolutePath());
                handleSdkInitResult(serviceMsg);

                is.close();
                tempFile.delete();
            }
        } catch (IOException e) {
            Log.e(TAG, "SDK初始化失败", e);
        }
    }

    private void handleSdkInitResult(ServiceMsg<String> serviceMsg) {
        if (serviceMsg.getResultCode() == Constant.RETURN_SUCCESS) {
            checkUsbPermissions();
        } else {
            Log.e(TAG, "掌纹模块初始化失败: " + serviceMsg.getMessageTip());
        }
    }

    private void checkUsbPermissions() {
        HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
        if (!deviceList.isEmpty()) {
            for (String deviceKey : deviceList.keySet()) {
                UsbDevice device = deviceList.get(deviceKey);

                int productId = device.getProductId();
                int vendorId = device.getVendorId();

                if (productId == PALM_USB_PRODUCT_ID && vendorId == PALM_USB_VENDOR_ID) {
                    // 判断是否有权限
                    if (usbManager.hasPermission(device)) {
                        hasUsbPermission = true;
                        startDeviceOperations();
                    } else {
                        requestUsbPermission(device);
                    }

                    break;
                }
            }
        }
    }

    private void requestUsbPermission(UsbDevice device) {
        PendingIntent permissionIntent = PendingIntent.getBroadcast(
                context,
                0,
                new Intent(ACTION_USB_PERMISSION),
                PendingIntent.FLAG_IMMUTABLE
        );
        usbManager.requestPermission(device, permissionIntent);
    }

    private void startDeviceOperations() {
        startThreads();
        initDeviceConnection();
    }

    private void startThreads() {
        if (palmRecognizeThread == null) {
            palmRecognizeThread = new PalmRecognizeThread();
            palmRecognizeThread.start();
        }
        if (palmDetectThread == null) {
            palmDetectThread = new PalmDetectThread();
            palmDetectThread.start();
        }
    }

    private void initDeviceConnection() {
        if (deviceTookImage == null) {
            deviceTookImage = new DeviceTookImage();
            deviceTookImage.start();
        }
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_palm, container, false);
        initializeUIComponents(root);
        setupEventListeners(root);
        return root;
    }

    private void initializeUIComponents(View root) {
        collectionTipTxt = root.findViewById(R.id.palm_collection_tip);
        palmPreviewImg = root.findViewById(R.id.palm_preview);

        collectionTipTxt.setText("准备中...");
    }

    private void setupEventListeners(View root) {
        root.findViewById(R.id.btn_back).setOnClickListener(v ->
                requireActivity().getSupportFragmentManager().popBackStack()
        );
    }

    // 掌纹处理线程
    private class PalmRecognizeThread extends Thread {
        private volatile boolean running = true;

        @Override
        public void run() {
            while (running) {
                try {
                    EnrollPicture picture = detectResultQueue.take();
                    unifiedApi.enroll(picture, 0);
                } catch (InterruptedException e) {
                    Log.e(TAG, "识别线程被中断", e);
                    break; // 退出循环
                } catch (Exception e) {
                    Log.e(TAG, "识别线程异常", e);
                }
            }
        }

        void stopThread() {
            running = false;
            interrupt();
        }
    }

    // 掌纹信息获取线程
    private class PalmDetectThread extends Thread {
        private volatile boolean running = true;

        private static final int MAX_FPS = 30;
        private long lastProcessTime = 0;

        @Override
        public void run() {
            while (running) {
                try {
                    // 控制帧率
                    long currentTime = System.currentTimeMillis();
                    if (currentTime - lastProcessTime < 1000/MAX_FPS) {
                        Thread.sleep(10);
                        continue;
                    }

                    lastProcessTime = currentTime;

                    byte[] img = PalmDeviceFrameUtil.takeComplexFrame();
                    if (img == null) continue;

                    processImageFrame(img);
                } catch (InterruptedException e) {
                    Log.e(TAG, "检测线程被中断", e);
                    break; // 退出循环
                } catch (Exception e) {
                    Log.e(TAG, "检测线程异常", e);
                }
            }
        }

        private void processImageFrame(byte[] img) {
            Bitmap rawBitmap = BitmapUtil.coverToBitmap(img, IMG_WIDTH, IMG_HEIGHT);

            ServiceMsg<DetectRoiResult> detectMsg = unifiedApi.detectRoi(img);
            String messageTip = detectMsg.getMessageTip();
            requireActivity().runOnUiThread(() ->
                    collectionTipTxt.setText(messageTip)
            );

            if (detectMsg.getResultCode() != Constant.RETURN_SUCCESS) return;

            DeviceMsg<byte[]> maskMsg = unifiedApi.maskImage(img);
            if (maskMsg.getResultCode() != Constant.RETURN_SUCCESS) return;

            // 更新掌纹信息预览
            updatePreviewImage(rawBitmap);
            queueEnrollPicture(detectMsg.getData(), maskMsg.getData());
        }

        void stopThread() {
            running = false;
            interrupt();
        }
    }

    // 掌纹图像绘制线程
    private class DeviceTookImage extends Thread {
        private volatile boolean running = true;

        @Override
        public void run() {
            while (running) {
                if (!hasUsbPermission || unifiedApi == null) {
                    sleepSafe(1000);
                    continue;
                }

                if (unifiedApi.isDeviceConnect()) {
                    handleConnectedDevice();
                } else {
                    initializeDevice();
                }
            }
        }

        private void handleConnectedDevice() {
            DeviceMsg<CaptureResult> captureMsg = unifiedApi.captureImage();

            switch (captureMsg.getResultCode()) {
                case SDPVDeviceConstant.RETURN_DEVICE_SUCCESS:
                    picTookSuccess(captureMsg.getData());
                    break;
                case SDPVDeviceConstant.RETURN_DEVICE_ERROR_DEVICE_NOT_TRIGGERED:
                    picTookNone(captureMsg.getData().getProximity_intensity());

                    requireActivity().runOnUiThread(() -> {
                        collectionTipTxt.setText("未检测到手掌...");
                    });

                    break;
                default:
                    Log.e(TAG, "设备取图失败: " + captureMsg.getMessageTip());
                    break;
            }
        }

        private void initializeDevice() {
            DeviceMsg<String> initMsg = unifiedApi.initDevice(context);
            if (initMsg.resultCode != SDPVDeviceConstant.RETURN_DEVICE_SUCCESS) {
                Log.e(TAG, "设备初始化失败: " + initMsg.messageTip);
            }
        }

        void stopThread() {
            running = false;
            interrupt();
        }
    }

    /**
     * 取图成功处理
     */
    protected void picTookSuccess(CaptureResult result) {
        if (Objects.isNull(collectionTipTxt)) {
            return;
        }

        if (result.getProximity_intensity() > PALM_DETECT_MAX) {
            requireActivity().runOnUiThread(() -> {
                collectionTipTxt.setText("距离过近，请正确放置手掌");
            });
        } else {
            PalmDeviceFrameUtil.addImageFrame(result.getImage());
        }
    }

    /**
     * 取图失败处理
     */
    protected void picTookNone(int intensity) {
        if (Objects.isNull(collectionTipTxt)) {
            return;
        }

        if (intensity > PALM_DETECT_MAX) {
            requireActivity().runOnUiThread(() -> {
                collectionTipTxt.setText("距离过近，请正确放置手掌");
            });
        }

        requireActivity().runOnUiThread(() -> {
            palmPreviewImg.setImageDrawable(colorDrawable);
        });
    }

    // 辅助方法
    private void updatePreviewImage(Bitmap bitmap) {
        requireActivity().runOnUiThread(() -> {
            if (palmPreviewImg != null && bitmap != null) {
                palmPreviewImg.setImageBitmap(bitmap);
            }
        });
    }

    private void queueEnrollPicture(DetectRoiResult roiResult, byte[] maskImg) {
        try {
            detectResultQueue.put(new EnrollPicture(roiResult.getImageRoi(), maskImg));
        } catch (InterruptedException e) {
            Log.e(TAG, "队列插入失败", e);
        }
    }

    private void sleepSafe(long millis) {
        try {
            Thread.sleep(millis);
        } catch (InterruptedException e) {
            Log.d(TAG, "线程休眠中断");
        }
    }

    private void showPermissionDenied() {
        requireActivity().runOnUiThread(() ->
                collectionTipTxt.setText("需要USB权限才能继续操作")
        );
    }

    @Override
    public void onDestroy() {
        cleanUpResources();
        super.onDestroy();
    }

    private void cleanUpResources() {
        // 停止线程
        if (palmRecognizeThread != null) {
            palmRecognizeThread.stopThread();
            try {
                palmRecognizeThread.join(500);
            } catch (InterruptedException e) {
                Log.e(TAG, "等待识别线程停止时中断", e);
            }
        }
        if (palmDetectThread != null) {
            palmDetectThread.stopThread();
            try {
                palmDetectThread.join(500);
            } catch (InterruptedException e) {
                Log.e(TAG, "等待检测线程停止时中断", e);
            }
        }
        if (deviceTookImage != null) {
            deviceTookImage.stopThread();
            try {
                deviceTookImage.join(500);
            } catch (InterruptedException e) {
                Log.e(TAG, "等待图像线程停止时中断", e);
            }
        }

        // 清理SDK
        if (unifiedApi != null) {
            unifiedApi.terminateDevice();
            PalmDeviceFrameUtil.resetQueue();
        }

        // 注销广播接收器
        if (usbPermissionReceiver != null) {
            context.unregisterReceiver(usbPermissionReceiver);
        }

        detectResultQueue.clear();
    }
}